<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <input type="file">
  <button id="btn">上传</button>
  <script>
    function request({
      url,
      method = "post",
      data,
      headers = {},
      onProgress = e => e,
      requestList
    }) {
      return new Promise(resolve => {
        const xhr = new XMLHttpRequest();
        xhr.open(method, 'https://jsonplaceholder.typicode.com/posts/');
        Object.keys(headers).forEach(key =>
          xhr.setRequestHeader(key, headers[key])
        );
        xhr.upload.onprogress = onProgress
        xhr.send(data);
        xhr.onload = e => {
          resolve({
            data: e.target.response
          });
        };
      });
    }
    function readFileToArrayBuffer(file) {
      return new Promise((resolve, reject) => {
        const reader = new FileReader()

        reader.onload = function (e) {
          resolve(e.target.result)
        }
        reader.readAsArrayBuffer(file)
      })
    }
    function arrayBufferToHexString(arrayBuffer) {
      const uint8Array = new Uint8Array(arrayBuffer);
      let hexString = '';
      for (let i = 0; i < uint8Array.length; i++) {
        const hex = uint8Array[i].toString(16).padStart(2, '0');
        hexString += hex;
      }
      return hexString;
    }
    function handleFileChange(event) {
      const file = event.target.files[0];  // 获取选中的文件
      fileChunksList = createFileChunk(file)
      if (file) {
        readFileToArrayBuffer(file)
          .then(arrayBuffer => {
            const hexString = arrayBufferToHexString(arrayBuffer);
            forData.append('file', hexString)
          })
          .catch(error => {
            console.error('文件读取失败:', error);
          });
      } else {
        setFileContent('请选择一个文件');
      }
    }
    // 创建文件分片
    function createFileChunk(file, size = 10 * 1000) {
      const fileSize = file.size
      size = file.size
      const chunkSize = size
      const chunkTotal = Math.ceil(fileSize / chunkSize)
      let cur = 0
      const fileChunkList = []
      while (cur < fileSize) {
        fileChunkList.push({ file: file.slice(cur, cur + chunkSize) })
        cur += chunkSize
      }
      return fileChunkList
    }
    // 分片上传
    async function uploadChunks(data) {
      const requestList = []
      // 上传前 请求接口返回已上传的文件名（续传）
      const uploadNameList = []
      data.forEach(({ chunk, hash, index }) => {
        // if(uploadedList.includes(hash))
        const formData = new FormData()
        formData.append('chunk', chunk)
        formData.append('hash', hash)
        requestList.push(request({
          data: formData,
          onProgress: createProgressHandler(fileChunksList[index])
        }))

        // 创建进度条
      })
      await Promise.all(requestList)
      // 合并请求
      await mergeRequest()
    }
    // 处理上传
    function handleUpload() {
      fileChunksList = fileChunksList.map(({ file }, index) => {
        return {
          chunk: file,
          index,
          hash: 'aaa' + '-' + index,
          percentage: 0
        }
      })
      uploadChunks(fileChunksList)
    }

    // 合并请求
    function mergeRequest() {
      request({
        data: JSON.stringify({ a: 123 }),
        headers: {
          "content-type": "application/json"
        }
      })
    }

    function createProgressHandler(item) {
      return e => {
        item.percentage = Math.ceil(e.loaded / e.total) * 100
        console.log(`上传进度:${item.percentage}%`);
      }
    }

    function uploadPercentage() {
      if (!fileChunksList.length) return 0;
      const loadedSize = fileChunksList
        .map(item => item.size * item.percentage)
        .reduce((acc, cur) => acc + cur);
      return parseInt((loadedSize / size).toFixed(2));
    }

    var forData = new FormData()
    let fileChunksList = []
    let size
    let input = document.querySelector('input')
    let btn = document.getElementById('btn')
    input.onchange = handleFileChange
    btn.onclick = handleUpload
  </script>
</body>

</html>